[情境劇場]
解師傅:嘿!想跟你調整一下菜盤數量,今天會請六月天樂團來表演
小當家:這個昨天不是講過了!?更新後的菜色我已經在準備了
解師傅:恩~對…只是不一樣的是..他們會包遊覽車過來,本來一桌的菜要變三桌了…
小當家:我懷疑他們是來蹭飯的吧!!!
基本上 useCallback
的目的就跟 useMemo
一樣,都是為了儲存記憶體的 Memorized Hook,只差在 useMemo
是回傳值,而 useCallback
是回傳 callback function,在 dependencies 沒有改變的情況下,把某個 function 保存下來,減少不必要的重新渲染
useCallback
方法dependencies
陣列import { useCallback } from "react";
const memoizedValue = useCallback (() => { doSomething(a) }, [a]);
第一個參數為函式,函式回傳不必要重新渲染的程式
第二個參數為 dependencies 陣列,useCallback 會依 dependencies
陣列去做比對差異,如果 dependencies 有變動,才會重新渲染,並回傳 callback function
如沒有 dependencies,則放空陣列,每次 render 時都會計算新的值。
state
或 props
來創建函數,需要使用到緩存函數的地方Object、 Array 因為是 by reference ,所以使用 useMemo 包裝,而 useCallback 也是一樣意思, useCallback 是把function
儲存起來再來做 function 的比對, function 也是 by reference,雖然是一樣的內容,但經過比對會是不一樣的 function
const functionOne = function() {
return 1;
};
const functionTwo = function() {
return 1;
};
console.log(functionOne === functionTwo); // false
App.js
import { useState } from "react";
import Child from "./components/Child";
function App() {
const [count, setCount] = useState(0);
const [value, setValue] = useState("");
const childCount = () => {
return [count + 1, count + 2, count + 3];
};
return (
<div>
<h1>現在號碼:{count}</h1>
<input
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
placeholder="無關緊要的 input"
/>
<Child childCount={childCount} />
<button
onClick={() => {
setCount((state) => state + 1);
}}
>
下一位
</button>
</div>
);
}
export default App;
components/Child.js
import { useEffect, useState } from "react";
const Child = (props) => {
const { childCount } = props;
const [count, setCount] = useState([]);
useEffect(() => {
console.log("render Child");
setCount(childCount());
}, [childCount]);
return <h1>排隊號碼:{count.join(", ")}</h1>;
};
export default Child;
簡單說明情境:
現在我們點擊下一位,也會很正常的渲染 Child 組件
但在輸入 input 時,發生了什麼事你應該也猜到了!
沒錯!明明跟組件無關,但輸入 input 時也 render 了 Child 組件,
這時我們可以用 useCallback
來解決~
const childCount = useCallback(() => {
return [count + 1, count + 2, count + 3];
}, [count]);
現在輸入 input 也不會影響到 Child 組件囉!用 useCallback 包住以確保 count 變動才會重新渲染
useCallback 跟 useMemo 用法其實大同小異,
其實 useCallback(fn, deps)
就同等於 useMemo(() => fn, deps)
他們有相同的特性,當然同樣的也不要過度使用,最好是用在執行速度很慢、變動性不大的函式,以減少重新渲染的目的
本文將同步更新至我的部落格
Lala 的前端大補帖